package com.lotto.manager.admin.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.lotto.manager.admin.dao.BetErrorMapper;
import com.lotto.manager.admin.dao.BetMapper;
import com.lotto.manager.admin.dto.BetDto;
import com.lotto.manager.admin.entity.db.Alloc;
import com.lotto.manager.admin.entity.db.Astrict;
import com.lotto.manager.admin.entity.db.Bet;
import com.lotto.manager.admin.entity.db.BetError;
import com.lotto.manager.admin.entity.db.Item;
import com.lotto.manager.admin.entity.db.Odds;
import com.lotto.manager.admin.entity.db.Play;
import com.lotto.manager.admin.service.AllocService;
import com.lotto.manager.admin.service.AstrictService;
import com.lotto.manager.admin.service.BetService;
import com.lotto.manager.admin.service.OddsService;
import com.lotto.manager.admin.system.SystemData;
import com.lotto.manager.common.constant.SystemConstant;
import com.lotto.manager.common.utils.ArithUtil;

public class BetServiceImpl implements BetService {

	@Autowired
	private BetMapper betMapper;

	@Autowired
	private BetErrorMapper betErrorMapper;

	@Autowired
	private AllocService allocService;

	@Autowired
	private AstrictService astrictService;

	@Autowired
	private OddsService oddsService;

	@Override
	public List<String> beting(Integer userid, List<BetDto> bets) {
		List<String> betreturn = new ArrayList<String>();
		for (BetDto betdto : bets) {
			betreturn.add(beting(userid, betdto));
		}
		return betreturn;
	}

	@Override
	public String beting(Integer userid, BetDto betdto) {
		Alloc alloc = allocService.findAccountByUserid(userid);
		if (null == alloc)
			return SystemConstant.BET_STATUS_EMPTY;
		String betStatus = restrict(betdto, alloc);
		// 如果验证条件有错误，
		if (!SystemConstant.BET_STATUS_ATTEST.equals(betStatus)) {
			BetError bet = createDtoToBetError(alloc, betdto, betStatus);
			betErrorMapper.insert(bet);
			return betStatus;
		}
		// 创建list的原因是 想批量插入
		List<Bet> bets = new ArrayList<Bet>();
		Bet bet = createDtoToBet(betdto, alloc);
		bets.add(bet);
		Astrict astrict = astrictService.findAstrict(alloc.getUaccId(),
				betdto.getPalyID());
		sumPlayUsed(astrict, bet.getMoney());

		while (0 != alloc.getLeaderId()) {
			Astrict bhastrict = astrictService.findAstrict(alloc.getLeaderId(),
					betdto.getPalyID());
			Double bhmoney = sumBetMoneyByUserid(alloc.getLeaderId(), bets);
			if (0D != bhmoney) {
				Bet bhbet = accumUsed(bhastrict, betdto, bhmoney);
				if (null != bhbet) {
					bets.add(bhbet);
				}
			}
			alloc = allocService.findAccountByUserid(alloc.getLeaderId());
		}
		// 此处保存所有的注单
		// betMapper.insert(bets);
		
		//后台执行
		astrict = astrictService.findAstrict(SystemConstant.SYSTEM_ADMIN_USERID,
				betdto.getPalyID());
		Double adminMoney = sumBetMoneyByUserid(SystemConstant.SYSTEM_ADMIN_USERID, bets);
		sumPlayUsed(astrict,adminMoney);
		return SystemConstant.BET_STATUS_SUCCEED;
	}

	// ==================================下面静态方法=========================================
	/**
	 * 
	* 方法名称: accumUsed
	* 描述:获取并补货注单
	* 参数：@param astrict
	* 参数：@param betdto
	* 参数：@param money
	* 参数：@return 
	* @throws
	 */
	private Bet accumUsed(Astrict astrict, BetDto betdto, Double money) {
		if (null != astrict) {
			sumPlayUsed(astrict, money);
			if (!SystemConstant.USER_TYPE_HY.equals(astrict.getUserType())) {
				astrict.setMaticUsed(ArithUtil.add(astrict.getMaticUsed(),
						money));
				Alloc alloc = allocService.findAccountByUserid(astrict
						.getUaccId());
				if (SystemConstant.SUCCEED.equals(alloc.getPatch())) {
					if ((astrict.getAutoMatic() != 0 && astrict.getMaticUsed() > astrict
							.getAutoMatic())) {
						Double betmoney = 0D;
						if (!astrict.getMaticfull()) {
							astrict.setMaticfull(true);
							betmoney = ArithUtil.sub(astrict.getMaticUsed(),
									astrict.getAutoMatic());
						} else {
							betmoney = money;
						}
						BetDto bhbet = copyBetDto(betdto);
						bhbet.setUserID(astrict.getUaccId());
						bhbet.setMoney(betmoney);
						bhbet.setBetType(SystemConstant.BET_REPAIR);
						Bet bet = createDtoToBet(bhbet, alloc);
						return bet;
					}
				}

			}
		}
		return null;
	}

	/**
	 * 
	* 方法名称: sumBetMoneyByUserid
	* 描述:累计所有投注金额
	* 参数：@param userid
	* 参数：@param bets
	* 参数：@return 
	* @throws
	 */
	private Double sumBetMoneyByUserid(Integer userid, final List<Bet> bets) {
		Double sumMoney = 0D;
		for (Bet bet : bets) {
			if (bet.getDlid() == userid) {
				ArithUtil.add(ArithUtil.mul(bet.getMoney(), bet.getDlzdbl()),
						sumMoney);
			} else if (bet.getZdid() == userid) {
				ArithUtil.add(ArithUtil.mul(bet.getMoney(), bet.getZdzdbl()),
						sumMoney);
			} else if (bet.getGdid() == userid) {
				ArithUtil.add(ArithUtil.mul(bet.getMoney(), bet.getGdzdbl()),
						sumMoney);
			} else if (bet.getDgid() == userid) {
				ArithUtil.add(ArithUtil.mul(bet.getMoney(), bet.getDgzdbl()),
						sumMoney);
			}else if(SystemConstant.SYSTEM_ADMIN_USERID == userid){
				ArithUtil.add(ArithUtil.mul(bet.getMoney(), bet.getGszdbl()),
						sumMoney);
			}
		}
		return sumMoney;
	}
	
	/**
	 * 
	* 方法名称: sumPlayUsed
	* 描述:计算玩法累计值
	* 参数：@param astrict
	* 参数：@param money 
	* @throws
	 */
	private void sumPlayUsed(Astrict astrict, Double money) {
		if (null != astrict) {
			astrict.setPlayUsed(astrict.getPlayUsed() + money);
			if (astrict.getPlayUsed() > astrict.getPlayMax()) {
				astrict.setPlayfull(true);
			}
		}
	}
	
	/**
	 * 
	* 方法名称: copyBetDto
	* 描述:因为要走飞所以生成一个走飞注单dto
	* 参数：@param betdto
	* 参数：@return 
	* @throws
	 */
	private BetDto copyBetDto(BetDto betdto) {
		BetDto bet = new BetDto();
		bet.setItems(betdto.getItems());
		bet.setBetType(betdto.getBetType());
		bet.setContent(betdto.getContent());
		bet.setPalyID(betdto.getPalyID());
		bet.setOdds(betdto.getOdds());
		return bet;
	}

	/**
	 * 
	* 方法名称: findAstrict
	* 描述:查询限制 
	* 参数：@param alloc
	* 参数：@param play
	* 参数：@return 
	* @throws
	 */
	private List<Astrict> findAstrict(Alloc alloc, Integer play) {
		List<Integer> users = getSuperiorByAccount(alloc);
		return astrictService.findAstricts(play, users);
	}

	/**
	 * 
	* 方法名称: getPlayidsByBetDtos
	* 描述:根据bet获取玩法id
	* 参数：@param bets
	* 参数：@return 
	* @throws
	 *//*
	private List<Integer> getPlayidsByBetDtos(List<BetDto> bets) {
		List<Integer> plays = new ArrayList<Integer>();
		for (BetDto betDto : bets) {
			plays.add(betDto.getPalyID());
		}
		return plays;
	}*/

	/**
	 * 
	* 方法名称: getSuperiorByAccount
	* 描述::据帐号获取上下级id
	* 参数：@param alloc
	* 参数：@return 
	* @throws
	 */
	private List<Integer> getSuperiorByAccount(Alloc alloc) {
		List<Integer> users = new ArrayList<Integer>();

		if (alloc.getDgdId() != 0) {
			users.add(alloc.getDgdId());
		}

		if (alloc.getGdId() != 0) {
			users.add(alloc.getGdId());
		}

		if (alloc.getZdId() != 0) {
			users.add(alloc.getZdId());
		}

		if (alloc.getDlId() != 0) {
			users.add(alloc.getDlId());
		}

		return users;

	}

	/**
	 * 
	* 方法名称: findReturns
	* 描述:上下级退水
	* 参数：@param alloc
	* 参数：@param astricts
	* 参数：@return 
	* @throws
	 */
	private Double[] findReturns(Alloc alloc, List<Astrict> astricts) {
		Double[] reutrns = new Double[] { 0D, 0D, 0D, 0D, 0D };// 默认为0
		for (Astrict astrict : astricts) {

			if (alloc.getDgdId() == astrict.getUaccId()) {
				if (SystemConstant.BET_TYPE_A.equals(alloc.getType())) {
					reutrns[4] = astrict.getAreturn();
				} else if (SystemConstant.BET_TYPE_B.equals(alloc.getType())) {
					reutrns[4] = astrict.getBreturn();
				} else if (SystemConstant.BET_TYPE_C.equals(alloc.getType())) {
					reutrns[4] = astrict.getCreturn();
				} else if (SystemConstant.BET_TYPE_D.equals(alloc.getType())) {
					reutrns[4] = astrict.getDreturn();
				} else {
					reutrns[4] = astrict.getAreturn();
				}
			} else if (alloc.getGdId() == astrict.getUaccId()) {
				if (SystemConstant.BET_TYPE_A.equals(alloc.getType())) {
					reutrns[3] = astrict.getAreturn();
				} else if (SystemConstant.BET_TYPE_B.equals(alloc.getType())) {
					reutrns[3] = astrict.getBreturn();
				} else if (SystemConstant.BET_TYPE_C.equals(alloc.getType())) {
					reutrns[3] = astrict.getCreturn();
				} else if (SystemConstant.BET_TYPE_D.equals(alloc.getType())) {
					reutrns[3] = astrict.getDreturn();
				} else {
					reutrns[3] = astrict.getAreturn();
				}
			} else if (alloc.getZdId() == astrict.getUaccId()) {
				if (SystemConstant.BET_TYPE_A.equals(alloc.getType())) {
					reutrns[2] = astrict.getAreturn();
				} else if (SystemConstant.BET_TYPE_B.equals(alloc.getType())) {
					reutrns[2] = astrict.getBreturn();
				} else if (SystemConstant.BET_TYPE_C.equals(alloc.getType())) {
					reutrns[2] = astrict.getCreturn();
				} else if (SystemConstant.BET_TYPE_D.equals(alloc.getType())) {
					reutrns[2] = astrict.getDreturn();
				} else {
					reutrns[2] = astrict.getAreturn();
				}
			} else if (alloc.getDlId() == astrict.getUaccId()) {
				if (SystemConstant.BET_TYPE_A.equals(alloc.getType())) {
					reutrns[1] = astrict.getAreturn();
				} else if (SystemConstant.BET_TYPE_B.equals(alloc.getType())) {
					reutrns[1] = astrict.getBreturn();
				} else if (SystemConstant.BET_TYPE_C.equals(alloc.getType())) {
					reutrns[1] = astrict.getCreturn();
				} else if (SystemConstant.BET_TYPE_D.equals(alloc.getType())) {
					reutrns[1] = astrict.getDreturn();
				} else {
					reutrns[1] = astrict.getAreturn();
				}
			} else if (alloc.getUaccId() == astrict.getUaccId()) {
				if (SystemConstant.BET_TYPE_A.equals(alloc.getType())) {
					reutrns[0] = astrict.getAreturn();
				} else if (SystemConstant.BET_TYPE_B.equals(alloc.getType())) {
					reutrns[0] = astrict.getBreturn();
				} else if (SystemConstant.BET_TYPE_C.equals(alloc.getType())) {
					reutrns[0] = astrict.getCreturn();
				} else if (SystemConstant.BET_TYPE_D.equals(alloc.getType())) {
					reutrns[0] = astrict.getDreturn();
				} else {
					reutrns[0] = astrict.getAreturn();
				}
			}
		}
		return reutrns;
	}
	
	/**
	 * 
	* 方法名称: restrict
	* 描述:检查下注用户的限制
	* 参数：@param betdto
	* 参数：@param alloc
	* 参数：@return 
	* @throws
	 */
	
	private String restrict(BetDto betdto, Alloc alloc) {
		Play play = SystemData.findPlay(betdto.getPalyID());
		if (null == play) {
			return SystemConstant.BET_STATUS_EMPTY;
		}
		// 判断玩法是否开放
		if (!SystemConstant.PLAYOPEN.equals(play.getPlayOpen())) {
			return SystemConstant.BET_STATUS_NOOPEN;
		}

		Astrict astrict = astrictService.findAstrict(betdto.getPalyID(),
				alloc.getUaccId());
		// 判断最小投注最大投注和单项投注
		if (astrict.getBetMin() > betdto.getMoney()) {
			return SystemConstant.BET_STATUS_MIN;
		}

		if (astrict.getBetMax() < betdto.getMoney()) {
			return SystemConstant.BET_STATUS_MAX;
		}

		if ((astrict.getPlayMax() - astrict.getPlayUsed()) < betdto.getMoney()) {
			return SystemConstant.BET_STATUS_SINGLE;
		}
		// 只有普通下注下有信用额的限制。补货不用信用额
		if (SystemConstant.BET_NORMAL.equals(betdto.getBetType())) {
			if (alloc.getCredit() < betdto.getMoney()) {
				return SystemConstant.BET_STATUS_SINGLE;
			}
		}

		if (!SystemConstant.ODDS_MORE.equals(play.getMoreOdds())) {
			Item item = SystemData.findItem(betdto.getItems()[0]);
			Odds odds = oddsService.findOddsByItemid(item.getItemId());
			if (!compare(
					ArithUtil.sub(odds.getOdds(), astrict.getSumCatOdds()),
					betdto.getOdds()[0])) {
				return SystemConstant.BET_STATUS_ODDS;
			}

			if (SystemConstant.ODDS_TWO.equals(play.getMoreOdds())) {
				if (betdto.getOdds().length != 2
						|| !compare(
								ArithUtil.sub(odds.getOdds(),
										astrict.getSumCatOdds()),
								betdto.getOdds()[1])) {
					return SystemConstant.BET_STATUS_ODDS;
				}
			}
		} else {
			Double[] oddss = filterOdds(betdto.getItems());
			double d1 = ArithUtil.add(oddss);
			double d2 = ArithUtil.add(betdto.getOdds());
			if (!compare(d1, d2)) {
				return SystemConstant.BET_STATUS_ODDS;
			}
		}
		return SystemConstant.BET_STATUS_ATTEST;
	}

	/**
	 * 
	* 方法名称: compare
	* 描述:比较两个赔率是否相同 
	* 参数：@param d1
	* 参数：@param d2
	* 参数：@return 
	* @throws
	 */
	private boolean compare(Double d1, Double d2) {
		if (ArithUtil.compareTo(d1, d2) == 0) {
			return true;
		} else {
			return false;
		}

	}
	
	/**
	 * 
	* 方法名称: filterOdds
	* 描述:通过玩法选项得到所有的赔率
	* 参数：@param itemids
	* 参数：@return 
	* @throws
	 */
	private Double[] filterOdds(Integer[] itemids) {
		Double[] oddss = new Double[itemids.length];
		for (int i = 0; i < itemids.length; i++) {
			Item item = SystemData.findItem(itemids[i]);
			Odds odds = oddsService.findOddsByItemid(item.getItemId());
			oddss[i] = odds.getOdds();
		}
		return oddss;
	}

	/**
	 * 
	* 方法名称: createDtoToBet
	* 描述:创建注单
	* 参数：@param betDto
	* 参数：@param alloc
	* 参数：@return 
	* @throws
	 */
	private Bet createDtoToBet(BetDto betDto, Alloc alloc) {
		List<Astrict> astricts = findAstrict(alloc, betDto.getPalyID());
		Double[] returnd = findReturns(alloc, astricts);
		if (returnd.length != 5) {
			return null;
		}
		Bet bet = new Bet();
		bet.setUaccId(alloc.getUaccId());
		bet.setUserType(alloc.getUserType());

		Item item = SystemData.findItem(betDto.getItems()[0]);
		bet.setGameId(item.getGameId());
		bet.setPlayId(item.getPlayId());
		bet.setItemId(item.getItemId());
		bet.setBetTime(new Date());
		double odds = 0D;
		double odds2 = 0D;
		if (!SystemConstant.ODDS_MORE.equals(item.getPlay().getMoreOdds())) {
			odds = betDto.getOdds()[0];
			if (SystemConstant.ODDS_TWO.equals(item.getPlay().getMoreOdds())
					&& betDto.getOdds().length == 2) {
				odds2 = betDto.getOdds()[1];
			}
		} else {
			odds = ArithUtil.add(betDto.getOdds());
			bet.setOddsSet(betDto.getOdds().toString());
		}
		bet.setOdds1(odds);
		bet.setOdds2(odds2);
		bet.setMoney(betDto.getMoney());
		bet.setBetType(SystemConstant.BET_NORMAL);
		bet.setBetClass(alloc.getType());
		bet.setPlayName("");
		String content = "";
		if (betDto.getContent().length > 1) {
			for (String temContent : betDto.getContent()) {
				content += temContent;
			}
		} else {
			content = betDto.getContent()[0];
		}
		bet.setContent(content);

		bet.setDlzdbl(alloc.getDlZc());
		bet.setZdzdbl(alloc.getZdZc());
		bet.setGdzdbl(alloc.getGdZc());
		bet.setDgzdbl(alloc.getDgZc());
		bet.setGszdbl(alloc.getGsZc());

		bet.setUserReturn(returnd[0] * betDto.getMoney());

		bet.setDlyj(betDto.getMoney()
				* (returnd[1] - returnd[0])
				* (alloc.getGsZc() + alloc.getDgZc() + alloc.getGdZc() + alloc
						.getZdZc()));
		bet.setZdyj(betDto.getMoney() * (returnd[2] - returnd[1])
				* (alloc.getGsZc() + alloc.getDgZc() + alloc.getGdZc()));
		bet.setGdyj(betDto.getMoney() * (returnd[3] - returnd[2])
				* (alloc.getGsZc() + alloc.getDgZc()));
		bet.setDgyj(betDto.getMoney() * (returnd[4] - returnd[3])
				* (alloc.getGsZc()));

		bet.setGsts(betDto.getMoney() * returnd[4]);
		bet.setHandsel(betDto.getMoney() * odds);

		return bet;
	}
	
	/**
	 * 创建错误注单 
	* 方法名称: createDtoToBetError
	* 描述:
	* 参数：@param alloc
	* 参数：@param betDto
	* 参数：@param errorContent
	* 参数：@return 
	* @throws
	 */
	private BetError createDtoToBetError(Alloc alloc, BetDto betDto,
			String errorContent) {
		BetError bet = new BetError();
		bet.setUaccId(alloc.getUaccId());
		bet.setUserType(alloc.getUserType());

		Item item = SystemData.findItem(betDto.getItems()[0]);
		bet.setGameId(item.getGameId());
		bet.setPlayId(item.getPlayId());
		bet.setItemId(item.getItemId());
		bet.setBetTime(new Date());
		double odds = 0D;
		double odds2 = 0D;
		if (!SystemConstant.ODDS_MORE.equals(item.getPlay().getMoreOdds())) {
			odds = betDto.getOdds()[0];
			if (SystemConstant.ODDS_TWO.equals(item.getPlay().getMoreOdds())
					&& betDto.getOdds().length == 2) {
				odds2 = betDto.getOdds()[1];
			}
		} else {
			odds = ArithUtil.add(betDto.getOdds());
			bet.setOddsSet(betDto.getOdds().toString());
		}
		bet.setOdds(odds);
		bet.setOdds2(odds2);
		bet.setMoney(betDto.getMoney());
		bet.setBetType(SystemConstant.BET_NORMAL);
		bet.setBetClass(alloc.getType());
		bet.setPlayName("");
		String content = "";
		if (betDto.getContent().length > 1) {
			for (String temContent : betDto.getContent()) {
				content += temContent;
			}
		} else {
			content = betDto.getContent()[0];
		}
		bet.setContent(content);

		return bet;
	}

}
